package zm.irc.ioc;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;

import zm.irc.ioc.pojo.WrapBeanObj;
import zm.irc.ioc.pojo.WrapClass;


public class ApplicationContext {

    private Map<String,WrapBeanObj> beanPoolClassName;
    private Map<String,WrapBeanObj> beanPoolBeanId;
    private Map<String,WrapClass> wrapClassCacheBeanId;
    private Map<String,WrapClass> wrapClassCacheClassName;

    private ApplicationInitalizion initalizion;
    public ApplicationContext(){
        this.beanPoolClassName = new HashMap<>();
        this.beanPoolBeanId = new HashMap<>();
        this.initalizion = new ApplicationInitalizion();
        this.wrapClassCacheBeanId = new HashMap<>();
        this.wrapClassCacheClassName = new HashMap<>();
    }

    Map<String,WrapBeanObj> getAllBeans(){
        return this.beanPoolBeanId;
    }

    public void putBean(WrapBeanObj bean){
        WrapClass clzz = bean.getWrapClass();
        String beanId = clzz.getBeanId();
        String className = clzz.getOriginClass().getName();
        this.putBeanByClassName(className, bean);
        this.putBeanById(beanId, bean);
    
    }

    public void addIntoCache(WrapClass wrapClass){
        this.wrapClassCacheBeanId.put(wrapClass.getBeanId(), wrapClass);
        this.wrapClassCacheClassName.put(wrapClass.getOriginClass().getName(), wrapClass);
      
    }

    private void putBeanById(String beanId,WrapBeanObj bean){
        this.beanPoolBeanId.put(beanId,bean);
    }
    private void putBeanByClassName(String className,WrapBeanObj bean){
        this.beanPoolClassName.put(className,bean);
    }

    public Object getBeanById(String beanId){
        WrapBeanObj obj = beanPoolBeanId.get(beanId);
        if(obj != null){
            return obj.getBeanObj();
        }
        Object beanObj = null;
        WrapBeanObj wrapBeanObj = this.initalizion.buildBean(this.wrapClassCacheBeanId.get(beanId), 
                                                                this, 
                                                                new HashMap<>(),
                                                                null);
        if(wrapBeanObj != null){
            beanObj = wrapBeanObj.getBeanObj();
        }
        
      
        return beanObj;
    }

    public Object getBeanByClass(String className){
        WrapBeanObj obj = beanPoolClassName.get(className);

        if (obj != null) {
            return obj.getBeanObj();
        }
        Object beanObj = null;

        WrapBeanObj wrapBeanObj = this.initalizion.buildBean(this.wrapClassCacheClassName.get(className),
                this,
                new HashMap<>(),
                null);
        if (wrapBeanObj != null) {
            beanObj = wrapBeanObj.getBeanObj();
        }

        return beanObj;
    }


    public <T> T getBeanById(String beanId, Class<T> clazz){
        Object beanObj = getBeanById(beanId);
        return beanObj == null? null :(T)beanObj;
       
    }

    public <T> T getBean(Class<T> clazz){
        if(clazz == null){
            return null;
        }
        Object beanObj = getBeanByClass(clazz.getName());              
        return beanObj == null? null : (T)beanObj;
    }


    public <T> List<T> getByType(Class<T> clazz){
        List<T> list = new ArrayList<>();
        Set<WrapClass> clazzs = WrapClass.getByType(clazz);
        if(CollectionUtils.isEmpty(clazzs)){
            return list;
        }

        for(WrapClass c : clazzs){
            list.add((T)this.getBean(c.getOriginClass()));
        }

        return list;
    }

}
